/// <reference path="./Transport.ts" />


namespace egret.socketio.engine {

    export abstract class Polling extends Transport {
        public static NAME: string = 'polling';

        private polling: boolean;

        private _readByte: ByteArray;
        private _writeByte: ByteArray;
        private _writeMessage: string = "";
        private _readMessage: string = "";

        constructor(opts: TransportUri) {
            super(opts);
            this.name = Polling.NAME;
            this._readByte = new ByteArray();
            this._writeByte = new ByteArray();
        }

        protected onData(data: any): void {
            let message: string;
            if (typeof data === 'string') {
                message = data;
            } else {
                this._readByte.position = 0;
                this._readByte._writeUint8Array(new Uint8Array(data));
                message = this._readByte.readUTF();
                this._readByte.clear();
            }

            this._onData(message);
        }

        protected _onData(message: string): void {
            let callbackfn = (packet: Packet, index: number, total: number): boolean => {
                if (this.readyState === _emReadyState.OPENING) {
                    this.onOpen();
                }

                if (packet.type === _emPacketType[_emPacketType.close]) {
                    this.onClose();
                    return false;
                }

                this.onPacket(packet);
                return true;
            };

            Parser.decodePayload(message, callbackfn);

            if (this.readyState != _emReadyState.CLOSED) {
                this.polling = false;
                this.emit(_emEvent.EVENT_POLL_COMPLETE);

                if (this.readyState === _emReadyState.OPEN) {
                    this.poll();
                } else {
                    console.debug("ignoring poll - transport state " + _emReadyState[this.readyState]);
                }
            }
        }

        protected write(packets: Packet[]): void {
            this.writable = false;
            let callbackfn = () => {
                this.writable = true;
                this.emit(_emEvent.EVENT_DRAIN);
            }
            Parser.encodePayload(packets, (data) => {
                this.doWrite(data, callbackfn);
            });
        }

        protected doOpen(): void {
            this.poll();
        }

        protected doClose(): void {

        }

        private poll(): void {
            console.debug("polling");
            this.polling = true;
            this.doPoll();
            this.emit(_emEvent.EVENT_POLL);
        }

        protected uri(): string {
            let uri = this.opts.clone();
            uri.addTrailingSlash();
            uri.addQueryParam('b64', 1);
            let schema = uri.secure ? 'https' : 'http';
            uri.protocol = schema;

            if (uri.timestampRequests) {
                uri.addQueryParam(uri.timestampParam, Yeast.yeast());
            }

            return uri.toString();
        }

        pause = (onPause: Function): void => {
            this.readyState = _emReadyState.PAUSING;

            let pause = () => {
                this.readyState = _emReadyState.PAUSED;
                onPause();
            }

            if (this.polling || !this.writable) {
                let total = 0;

                if (this.polling) {
                    total++;
                    this.once(_emEvent.EVENT_POLL_COMPLETE, () => {
                        --total || pause();
                    });
                }

                if (!this.writable) {
                    total++;
                    this.once(_emEvent.EVENT_DRAIN, () => {
                        --total || pause();
                    });
                }
            } else {
                pause();
            }

        }

        protected abstract doPoll(): void;
        protected abstract doWrite(data: string, fn: Function): void;
    }
}